#include "TDA_DNS.h"
#include "TDA_AB.h"
#include "TDAServidorInseguro.h"
#include <string.h>


/*  addDataToLogDNS
    Pre.: N/A
    Post.: Se agrego a la pila del DNS el elemento de log.
*/
void addDataToLogDNS(TDA_DNS* DNS, char* dominio);


/*  extraerSubDominio
    Pre.: N/A
    Post.: Devuelve el sub-dominio de una direccion dada.
*/
int extraerSubDominio(char* dominio, char subDominios[5][50]);

int comparar (void* uno, void* dos){

    return strcmp((char*)uno,(char*)dos);

}


int crearDNS (TDA_DNS* DNS){

    strcpy (DNS->ipAddress,DEFAULT_DNS);

    P_Crear( &(DNS->pilaLog) ,sizeof(TDADNSLog));

    DNS->ab = (TAB*) malloc (sizeof(TAB));
    DNS->qtyEventos = 0;
    ABO_Crear(DNS->ab, (&comparar));

    return EXIT_SUCCESS;
}


void destruirDNS (TDA_DNS* DNS){

    AB_Vaciar(DNS->ab);
    free(DNS->ab);
    if ( P_Vacia(DNS->pilaLog) )
        P_Vaciar( &(DNS->pilaLog) );

}


int existeDominio (TDA_DNS DNS, char* dominio){

    return buscarDatoPrimario(DNS.ab,&(DNS.ab->raiz),dominio);

}



int agregarDominio (TDA_DNS* DNS, char* dominio){

    TAB *arbolSigNivel;
    TAB *auxAB;
    void* server = NULL;
    int error, qty, z, search,i;
    char subDominios[5][50]={{0}};
    char auxDominio[50]={0};
    TDatoAB auxDato;

    arbolSigNivel = (TAB*) malloc(sizeof(TAB) );
    ABO_Crear(arbolSigNivel, (&comparar));

    server = malloc ( sizeof(TDAServidorInseguro) );

    qty = extraerSubDominio(dominio, subDominios);

    auxAB = DNS->ab;
    AB_MoverCte(auxAB,RAIZ,&error);
    auxDominio[0]='\0';

    for ( z = qty, i=0 ; z>0 ; z--, i++){

        strcat(auxDominio,subDominios[i]);

        /* Chequea si existe el elemento en el arbol */
        search = AB_obtenerPosicion(auxAB,&(auxAB->raiz),subDominios[z-1]);

        if ( auxAB->cte == NULL || search ){

            crearServidor( (TDAServidorInseguro*)server, auxDominio, DNS );

            auxDato.sigNivel = arbolSigNivel;
            strcpy(auxDato.dominio,subDominios[z-1]);
            auxDato.server = server;

            /* En caso de no exixtir ingresa el elemento con un nuevo sub-arbol y server */
            ABO_Insertar(auxAB, &auxDato, &error);

        }else{

            /* Si existe elimina la memoria asignada al sub arbol y al server y lo agrega
            utilizando el sub-arbol y el server existente en el nodo. */
            free ( arbolSigNivel );
            free ( server );

            arbolSigNivel = ((TDatoAB*)(auxAB->cte->dato))->sigNivel;

        }

        auxAB = arbolSigNivel;

        arbolSigNivel = (TAB*) malloc(sizeof(TAB) );
        if ( arbolSigNivel == NULL)
			return EXIT_FAILURE;

        ABO_Crear(arbolSigNivel, (&comparar));

        server = malloc ( sizeof(TDAServidorInseguro) );
        if ( server == NULL)
			return EXIT_FAILURE;

        strcat(auxDominio,".");

    }

    free ( arbolSigNivel );
    free ( server );

    return EXIT_SUCCESS;

}

void* obtenerValor(TDA_DNS *DNS, char* dominio, void* server){

    int error, qty, z, search;
    char subDominios[5][50];
    TAB *auxAB;

    auxAB = DNS->ab;
/*    printf("\n Writing to stack on DNS %p",DNS);
    addDataToLogDNS(DNS,dominio);
*/
    AB_MoverCte(auxAB,RAIZ,&error);
    qty = extraerSubDominio(dominio, subDominios);


    for ( z = qty ; z > 0 ; z--){

        /* Chequea si existe el elemento en el arbol */
        search = AB_obtenerPosicion(auxAB,&(auxAB->raiz),subDominios[z-1]);


        if ( auxAB->cte == NULL || search ){
            printf("\nNo existe el dominio: %s\n",subDominios[z-1]);
            return (void*)EXIT_FAILURE;

        }else{

            server = ((TDatoAB*)(auxAB->cte->dato))->server;
            auxAB = ((TDatoAB*)(auxAB->cte->dato))->sigNivel;
        }
    }

    return server;

}


void eliminarDominio(TDA_DNS *DNS, char* dominio){

    AB_BorrarElem(DNS->ab, dominio);
}


int escribirLogDNS(TDA_DNS servidor, FILE* archivo){


    int i=0;
    TDADNSLog logData;
    struct tm *date;

    for ( i=0 ; i < servidor.qtyEventos ; i++){

        P_Sacar( &(servidor.pilaLog), &logData);

        date = localtime ( &(logData.fechaHora) );

        fprintf(archivo,"<%d-%d-%d> <%02d:%02d:%02d> : se consulto el dominio <%s>\n",
                            (date->tm_year+1900),(date->tm_mon+1),date->tm_mday,date->tm_hour,
                            date->tm_min,date->tm_sec,logData.dominio);
    }

    P_Vaciar(&servidor.pilaLog);

    return EXIT_SUCCESS;


}
void addDataToLogDNS(TDA_DNS* DNS, char* dominio)
{

    TDADNSLog logData;

    time_t fechaHora;

    fechaHora = time(NULL);

    logData.fechaHora = fechaHora;
    strcpy(logData.dominio,dominio);

    P_Agregar( &(DNS->pilaLog), &logData);

    DNS->qtyEventos +=1;

}



int extraerSubDominio(char* dominio, char subDominios[5][50]){

    int i=0, j=0, k=0;
    char aux[50]={0};

    for (  ; i < (strlen(dominio)+1) ; i++){

        if ( dominio[i] == '.' ){

            aux[j] = '\0';

            for ( j = 0; j < (strlen(aux)+1) ; j++)
                subDominios[k][j] = aux[j];

            k++;
            j = 0;

        }else{
            aux[j] = dominio[i];
            j++;
        }
    }

    aux[j] = '\0';

    for ( j = 0; j < (strlen(aux)+1) ; j++)
        subDominios[k][j] = aux[j];

    k++;

    return k;

}


void* queryDNS(TDA_DNS *DNS, char* dominio, void* server){

    int error, qty, z, search;
    char subDominios[5][50];
    TAB *auxAB;

    auxAB = DNS->ab;
    addDataToLogDNS(DNS,dominio);

    AB_MoverCte(auxAB,RAIZ,&error);
    qty = extraerSubDominio(dominio, subDominios);


    for ( z = qty ; z > 0 ; z--){

        /* Chequea si existe el elemento en el arbol */
        search = AB_obtenerPosicion(auxAB,&(auxAB->raiz),subDominios[z-1]);


        if ( auxAB->cte == NULL || search ){
            printf("\nNo existe el dominio: %s\n",subDominios[z-1]);
            return (void*)EXIT_FAILURE;

        }else{

            server = ((TDatoAB*)(auxAB->cte->dato))->server;
            auxAB = ((TDatoAB*)(auxAB->cte->dato))->sigNivel;
        }
    }

    return server;

}
